package com.fishv.fishvdianping.service.impl;
import java.util.Date;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fishv.fishvdianping.common.BusinessException;
import com.fishv.fishvdianping.common.ErrorCode;
import com.fishv.fishvdianping.common.RedisConstant;
import com.fishv.fishvdianping.common.UserHolder;
import com.fishv.fishvdianping.mapper.SeckillVoucherMapper;
import com.fishv.fishvdianping.model.domain.SeckillVoucher;
import com.fishv.fishvdianping.model.domain.Voucher;
import com.fishv.fishvdianping.model.domain.VoucherOrder;
import com.fishv.fishvdianping.model.vo.UserVO;
import com.fishv.fishvdianping.service.SeckillVoucherService;
import com.fishv.fishvdianping.service.VoucherOrderService;
import com.fishv.fishvdianping.service.VoucherService;
import com.fishv.fishvdianping.utils.ILock;
import com.fishv.fishvdianping.utils.SimpleRedisLock;
import com.fishv.fishvdianping.utils.ThrowUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.aop.framework.AopContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
* @author yuwei
* @description 针对表【tb_seckill_voucher(秒杀优惠券表，与优惠券是一对一关系)】的数据库操作Service实现
* @createDate 2024-10-21 14:52:19
*/
@Service
public class SeckillVoucherServiceImpl extends ServiceImpl<SeckillVoucherMapper, SeckillVoucher>
    implements SeckillVoucherService {

    @Resource
    private VoucherService voucherService;
    @Resource
    VoucherOrderService voucherOrderService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RedissonClient redissonClient;



    @Override

    public Long getSecKillVoucher(Long id) {

        //1 看库存
        SeckillVoucher seckillVoucher = query().eq("voucher_id",id).one();
        ThrowUtils.throwIf(seckillVoucher == null, ErrorCode.NOT_FOUND_ERROR,"优惠券不存在");
        Voucher voucher = voucherService.getById(id);
        //1.1 库存不够
        ThrowUtils.throwIf(seckillVoucher.getStock()<1,ErrorCode.OPERATION_ERROR, "优惠卷抢完了");
        //2校验活动时间
        //2.1不在活动时间内
        ThrowUtils.throwIf(seckillVoucher.getBeginTime().isAfter(LocalDateTime.now()), ErrorCode.OPERATION_ERROR, "秒杀活动未开始");
        ThrowUtils.throwIf(seckillVoucher.getEndTime().isBefore(LocalDateTime.now()), ErrorCode.OPERATION_ERROR, "秒杀活动已结束");
        //下单
        UserVO user = UserHolder.getUser();
        SeckillVoucherService service  = (SeckillVoucherService)AopContext.currentProxy();
        Long orderId = null;
//        synchronized (user.getId().toString().intern()){
//            orderId =  service.createVoucherOrder(voucher.getId());
//        }
        //分布式锁
      //  ILock lock = new SimpleRedisLock(user.getId().toString(),stringRedisTemplate);
        //redisson
         RLock lock  = redissonClient.getLock(RedisConstant.VOUCHER_LOCK_KEY +user.getId().toString());
        if(lock.tryLock()){
            orderId =  service.createVoucherOrder(voucher.getId());
            lock.unlock();
        }else {
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"重复下单");
        }
        return orderId;
    }

    @Transactional
    @Override
    public Long createVoucherOrder(Long voucherId) {
        //3检查重复下单
        UserVO user = UserHolder.getUser();
        VoucherOrder voucherOrder = voucherOrderService.query().eq("user_id", user.getId()).eq("voucher_id", voucherId).one();
        //3.1已经下单
        ThrowUtils.throwIf(voucherOrder != null, ErrorCode.OPERATION_ERROR, "不能重复下单");
        //4下单
        //4.1扣库存
        boolean success = update().setSql("stock = stock - 1").eq("voucher_id", voucherId).gt("stock", 0).update();
        ThrowUtils.throwIf(!success, ErrorCode.OPERATION_ERROR, "库存不足");
        voucherOrder = new VoucherOrder();
        //4.2创建订单
        voucherOrder.setUserId(user.getId());
        voucherOrder.setVoucherId(voucherId);
        voucherOrder.setCreateTime(new Date());;
        voucherOrder.setUpdateTime(new Date());
        Boolean res = voucherOrderService.save(voucherOrder);
        ThrowUtils.throwIf(!res, ErrorCode.OPERATION_ERROR, "创建订单失败");
        //4.3返回订单id
        return voucherOrder.getId();
    }
}




